/**
 * 工具类
 */
export class ToolUtils {

  static oper = ['+', '-', '×', '÷', '(', ')', '#'];
  /**
   * 判断字符串是否属于操作符
   * @param ch 
   */
  static in(ch: string) {
    return this.oper.indexOf(ch) != -1;
  }
  /**
   * 判断优先级
   * @param theta1 
   * @param theta2 
   */
  static onPrecede0(theta1: string, theta2: string) {
    if((theta1 === '(' && theta2 === ')') || theta1 === '#' && theta2 === '#') {
      return '=';
    } else if (theta1 == '(' || theta1 == '#' || theta2 == '(' || (theta1 == '+' || theta1 == '-') && (theta2 == '×' || theta2 == '÷')) {
      return '<';
    }
    return '>';
  }

  static onPrecede(theta: string | undefined) {
    let x = -1;
    switch(theta) {
      case '(':
      case ')': {
        x = 0;
        break;
      }
      case '+':
      case '-': {
        x = 1;
        break;
      }
      case '×':
      case '÷': {
        x = 2;
        break;
      }
    }
    return x;
  }

  /**
   * 操作
   * @param first 
   * @param theta 
   * @param second 
   */
  static onOperate(first: string | undefined, theta: string | undefined, second: string | undefined) {
    if (first === undefined || theta === undefined || second === undefined) {
      return 0;
    }
    switch(theta) {
      case '+': {
        return Number(first) + Number(second);
      }
      case '-': {
        return Number(first) - Number(second);
      }
      case '×': {
        return Number(first) * Number(second);
      }
      case '/': {
        return Number(first) / Number(second);
      }
    }
    return 0;
  }
  /**
   * 计算表达式
   * @param str 表达式
   */
  static evaluateExpression0 (str: string) {
    console.warn(str);
    const OPTR = ['#'], OPND = [] as Array<string>;
    let theta, a, b, x;
    for (let i=0;i<str.length; ++i) {
      const item = str[i];
      console.warn(item);
      if ( item != '#' || OPTR[OPTR.length - 1] != '#') {
        if(!this.in(item)) {
          OPND.push(item);
        } else {
          console.warn(OPND);
          console.warn(this.onPrecede0(OPTR[OPTR.length - 1], item));
          switch(this.onPrecede0(OPTR[OPTR.length - 1], item)) {
            case '<': {
              OPTR.push(item);
              break;
            }
            case '>': {
              theta = OPTR.pop(); 
              b = OPND.pop();
              a = OPND.pop();
              OPND.push(this.onOperate(a, theta, b).toString());
              break;
            }
            case '=':{
              x = OPTR.pop();
              break;
            }
          }
        }
      }
    }
    console.warn(OPND);
    return OPND[OPND.length - 1];
  }

  static evaluateExpression (str: string) {
    const OPTR = [] as Array<string>,  OPND = [] as Array<string>;
    let d = '';
    for (let i=0;i<str.length; ++i) {
      let j = 0;
      if(!this.in(str[i])) {
        do {
          d += str[i];
          ++i;
          ++j;
        } while(i<str.length && !this.in(str[i]));
        --i;
        OPND.push(d);
        d = '';
      } else {
        if(OPTR.length<=0 || this.onPrecede(OPTR[OPTR.length - 1]) < this.onPrecede(str[i]) || str[i] == '(') {
          OPTR.push(str[i]);
        } else {
          if(str[i] == ')') {
            let numB = 1;
            while(numB) {
              if(OPTR[OPTR.length - 1] == '(') {
                let c = OPTR.pop();
                numB = 0;
              } else {
                let y = OPND.pop();
                let x = OPND.pop();
                let s = OPTR.pop();
                let sum = this.onOperate(x, s, y);
                OPND.push(sum.toString());
              }
            }
          } else {
            let y = OPND.pop();
            let x = OPND.pop();
            let s = OPTR.pop();
            let sum = this.onOperate(x, s, y);
            OPND.push(sum.toString());
            OPTR.push(str[i]);
          }
        }
      }
    }
    while(OPTR.length > 0) {
      let x = OPND.pop();
      let s = OPTR.pop();
      let y = OPND.pop();
      let sum;
      if(s == '-' || s == '÷') {
        sum = this.onOperate(y, s, x);
      } else {
        sum = this.onOperate(x, s, y);
      }
      OPND.push(sum.toString());
    }
    console.warn(OPND);
    console.warn(OPTR);
    return OPND[OPND.length - 1];
  }
}